package com.power.sifa.approve.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.aventrix.jnanoid.jnanoid.NanoIdUtils;
import com.plf.common.file.service.IFileService;
import com.plf.core.base.model.Ha_attachment;
import com.plf.core.base.model.Ha_user;
import com.plf.core.base.service.Ha_attachmentService;
import com.plf.core.base.service.Ha_userService;
import com.plf.core.common.service.BaseServiceImpl;
import com.power.sifa.approve.dao.Aprv_materials_optionsDao;
import com.power.sifa.approve.model.Aprv_materials_options;
import com.power.sifa.approve.model.Aprv_process_materials;
import com.power.sifa.approve.model.enumeration.Tp_procmaterialEnum;
import com.power.sifa.approve.model.pageInfo.Aprv_materials_optionsPageInfo;
import com.power.sifa.approve.service.Aprv_materials_optionsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 *  表单输入动态生成的材料文件业务层实现
 */
@Service
@Slf4j
public class Aprv_materials_optionsServiceImpl extends BaseServiceImpl implements Aprv_materials_optionsService {

    @Autowired
    private Aprv_materials_optionsDao dao;

    @Resource
    private IFileService fileService;

    @Resource
    private Ha_attachmentService ha_attachmentService;

//    @Resource
//    private Aprv_process_materialsService aprv_process_materialsService;

//    @Resource
//    private Aprv_materials_options_versionService aprv_materials_options_versionService;

    @Resource
    private Ha_userService ha_userService;

    @Override
    public Aprv_materials_options getById(Serializable id) {
        return dao.findById(id).orElse(null);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveOrUpdate(Aprv_materials_options aprv_materials_options) {
    	// save 如果数据库不存在这条数据，就会执行保存（即将这条数据插入到数据库）；如果数据库存在这条数据，就会根据主键去更新这条数据
        if (aprv_materials_options.getPrimaryKey() != null) {
        	 Aprv_materials_options aprv_materials_optionsfDb = dao.findById(aprv_materials_options.getPrimaryKey()).orElse(null);
             if(aprv_materials_optionsfDb != null) {
                BeanUtils.copyProperties(aprv_materials_options, aprv_materials_optionsfDb);
                dao.save(aprv_materials_optionsfDb);
                return;
             }
        }
        dao.save(aprv_materials_options);
    }

    @Override
    public void removeById(Serializable id) {
        dao.deleteById(id);
    }

    @Override
    public Page<Aprv_materials_options> findAll(Aprv_materials_optionsPageInfo pageInfo) {
        //排序等定义
        Sort sort;
        if("asc".equals(pageInfo.getOrder())) {
            sort = Sort.by(Sort.Direction.ASC, pageInfo.getSort());
        }else {
            sort = Sort.by(Sort.Direction.DESC, pageInfo.getSort());
        }
        //分页的定义
        Pageable pageable = PageRequest.of(pageInfo.getPageNumber()<=1 ? 0 : pageInfo.getPageNumber()-1, pageInfo.getPageSize(), sort);
        //查询条件
        Specification spec = this.createSpecification(pageInfo);
        return dao.findAll(spec, pageable);
    }
    
    @Transactional(rollbackFor = Exception.class)
    public void removeByIds(List<String> ids) {
        dao.removeByIds(ids);
    }
    
    @Override
	public List<Aprv_materials_options> findAll() {
		return dao.findAll();
	}
	
	@Override
	public void saveAll(List<Aprv_materials_options> list) {
		dao.saveAll(list);
	}


    @Override
    public List<Aprv_materials_options> findAllOptionsByApplyid(String applyid) {
        return dao.findAllOptionsByApplyid(applyid);
    }

    @Override
    public List<Aprv_materials_options> findAllOptionsByMaterialId(String materialId) {
        return dao.findAllOptionsByMaterialId(materialId);
    }

    @Override
    public Aprv_materials_options findOneOptionsByAttachId(String attachId) {
        List<Aprv_materials_options> result = dao.findAllOptionsByAttachId(attachId);
        return CollectionUtil.isNotEmpty(result) ? result.get(0) : null;
    }


    @Override
    public List<Aprv_materials_options> findAllOptionsByMaterialType(String applyid, Integer materialType) {
        return dao.findAllOptionsByMaterialType(applyid, materialType);
    }

    /**
     * FIXME: 之前用于表单编辑预览，后被在线编辑替代(弃用)
     * @param attachment
     * @param applyid
     * @param busiType
     * @param userId
     * @param userName
     * @param procmaterialEnum
     * @param docfield
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Aprv_materials_options saveOptionMaterial(Ha_attachment attachment, String applyid, Integer busiType,
                                                     String userId, String userName, Tp_procmaterialEnum procmaterialEnum, Map<String,Object> docfield) throws Exception {
        try {
//            Aprv_process_materials materialResult = this.aprv_process_materialsService.saveMaterial(attachment.getId(),
//                    applyid, busiType, userId, userName, procmaterialEnum);
//            String docFileStr = JSON.toJSONString(docfield);
//            // 记录当前的入参参数
//            Aprv_materials_options options = Aprv_materials_options.builder().id(applyid + NanoIdUtils.randomNanoId()).applyid(applyid).mattype(procmaterialEnum.getId())
//                    .materialid(materialResult.getId()).userid(userId).username(userName)
//                    .createtime(new Date()).docfiled(docFileStr).proctype(busiType).build();
//            this.saveOrUpdate(options);
//            // 记录当前的入参参数版本记录
//            Aprv_materials_options_version version = Aprv_materials_options_version.builder().id(applyid + NanoIdUtils.randomNanoId()).optionid(options.getId())
//                    .userid(userId).username(userName).createtime(new Date()).docfiled(docFileStr).build();
//            this.aprv_materials_options_versionService.saveOrUpdate(version);
//            return options;
            return null;
       } catch (Exception e) {
           e.printStackTrace();
           throw e;
       }
    }

    /**
     * FIXME: 之前用于表单编辑预览，后被在线编辑替代(弃用)
     * @param attachment
     * @param applyid
     * @param optionid
     * @param busiType
     * @param userId
     * @param userName
     * @param docfield
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Aprv_materials_options updateOptionMaterial(Ha_attachment attachment, String applyid, String optionid, Integer busiType,
                                                       String userId, String userName, Map<String, Object> docfield) throws Exception {
       try {
           // 获取之前版本的记录
//           Aprv_materials_options oldOptions = this.getById(optionid);
//           if (ObjectUtil.isNull(oldOptions)) {
//              throw new BusinessException("当前版本记录为空");
//           }
//           // 判断当前的材料类型
//            Tp_procmaterialEnum procmaterialEnum = Tp_procmaterialEnum.getById(oldOptions.getMattype());
//            if (ObjectUtil.isNull(procmaterialEnum)) {
//                throw new BusinessException("未查询到对应文件类型");
//            }
//           Aprv_process_materials oldMaterial = aprv_process_materialsService.getById(oldOptions.getMaterialid());
//           if (ObjectUtil.isNotNull(oldMaterial)) {
//               Ha_attachment ha_attachment = ha_attachmentService.getById(oldMaterial.getAttachid());
//               if (ha_attachment == null) {
//                   throw new BusinessException("未根据id找到文件");
//               }
//               String filename = ha_attachment.getPath();
//               // 删除之前保存的材料记录
//               boolean flag = fileService.removeFile(null, filename);
//               if (flag) {
//                   ha_attachmentService.removeById(oldMaterial.getAttachid());
//               } else {
//                   throw new BusinessException("文件删除失败");
//               }
//               aprv_process_materialsService.removeById(oldOptions.getMaterialid());
//           }
//           Aprv_process_materials materialResult = this.aprv_process_materialsService.saveMaterial(attachment.getId(),
//                   applyid, busiType, userId, userName, procmaterialEnum);
//           // 更新当前的入参参数和材料id
//           oldOptions.setMaterialid(materialResult.getId());
//           String docFileStr = JSON.toJSONString(docfield);
//           oldOptions.setDocfiled(docFileStr);
//           // 更新数据
//           this.saveOrUpdate(oldOptions);
//           // 重新记录一条版本记录
//           Aprv_materials_options_version version = Aprv_materials_options_version.builder().id(oldOptions.getApplyid() + NanoIdUtils.randomNanoId()).optionid(oldOptions.getId())
//                   .userid(userId).username(userName).createtime(new Date()).docfiled(docFileStr).build();
//           this.aprv_materials_options_versionService.saveOrUpdate(version);
//           return oldOptions;
           return null;
       }  catch (Exception e) {
           e.printStackTrace();
           throw e;
       }
    }

    /**
     * FIXME: 之前用于表单编辑预览，后被在线编辑替代(弃用)
     * @param attachment
     * @param applyid
     * @param optionid
     * @param busiType
     * @param docfield
     * @return
     * @throws Exception
     */
    @Override
    public Aprv_materials_options endOptionMaterial(Ha_attachment attachment, String applyid, String optionid, Integer busiType, Map<String, Object> docfield) throws Exception {
        try {
//            // 获取之前版本的记录
//            Aprv_materials_options oldOptions = this.getById(optionid);
//            if (ObjectUtil.isNull(oldOptions)) {
//                throw new BusinessException("当前版本记录为空");
//            }
//            // 判断当前的材料类型
//            Tp_procmaterialEnum procmaterialEnum = Tp_procmaterialEnum.getById(oldOptions.getMattype());
//            if (ObjectUtil.isNull(procmaterialEnum)) {
//                throw new BusinessException("未查询到对应文件类型");
//            }
//            Aprv_process_materials oldMaterial = aprv_process_materialsService.getById(oldOptions.getMaterialid());
//            if (ObjectUtil.isNotNull(oldMaterial)) {
//                Ha_attachment ha_attachment = ha_attachmentService.getById(oldMaterial.getAttachid());
//                if (ha_attachment == null) {
//                    throw new BusinessException("未根据id找到文件");
//                }
//                String filename = ha_attachment.getPath();
//                // 删除之前保存的材料记录
//                boolean flag = fileService.removeFile(null, filename);
//                if (flag) {
//                    ha_attachmentService.removeById(oldMaterial.getAttachid());
//                } else {
//                    throw new BusinessException("文件删除失败");
//                }
//                aprv_process_materialsService.removeById(oldOptions.getMaterialid());
//            }
//            Aprv_process_materials materialResult = this.aprv_process_materialsService.saveMaterial(attachment.getId(),
//                    applyid, busiType, oldOptions.getUserid(), oldOptions.getUsername(), procmaterialEnum);
//            // 更新当前的入参参数和材料id
//            oldOptions.setMaterialid(materialResult.getId());
//            String docFileStr = JSON.toJSONString(docfield);
//            oldOptions.setDocfiled(docFileStr);
//            // 更新数据
//            this.saveOrUpdate(oldOptions);
//            return oldOptions;
            return null;
        }  catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }


    /**
     * 生成对应的初始化版本记录
     * @param material
     * @param userId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void initMaterialOptions(Aprv_process_materials material, String userId) {
        // 查询当前userId的用户
        Ha_user user = ha_userService.getById(userId);
        if (ObjectUtil.isNotNull(material) && ObjectUtil.isNotNull(material.getFile())) {
            // 读取当前文件的流
            try {
                Ha_attachment attachment = material.getFile();
                // 重新获取ha_attachment对象的path，对象里返回的是绝对路径
                Ha_attachment noTranAttachment =  ha_attachmentService.getById(attachment.getId());
                if (ObjectUtil.isNotNull(noTranAttachment)) {
                    InputStream inputStream = fileService.getStream(noTranAttachment.getBucket(), noTranAttachment.getPath());
                    // 生成一份新的文件
                    Ha_attachment newAttachment = ha_attachmentService.upload(inputStream, noTranAttachment.getFilename());
                    // 新增一条记录
                    // 查询当前最大版本
                    Integer maxVersion = this.findMaxVersion(material.getId());
                    Integer version = ObjectUtil.isNotNull(maxVersion) ? maxVersion + 1 : 1;
                    Aprv_materials_options options = Aprv_materials_options.builder().id(material.getApplyid() + NanoIdUtils.randomNanoId()).applyid(material.getApplyid())
                            .mattype(material.getMattype()).materialid(material.getId()).userid(userId).username(ObjectUtil.isNotNull(user) ? user.getFullname() : null)
                            .createtime(new Date()).proctype(material.getType()).attachid(newAttachment.getId()).version(version).build();
                    this.saveOrUpdate(options);
                }
            } catch (IOException e) {
                e.printStackTrace();
                log.error("文件读取失败,无法生成对应的初始化版本记录");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public Integer findMaxVersion(String materialId) {
        return dao.findMaxVersion(materialId);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteMaterialOptions(String materialid) {
        List<Aprv_materials_options> options = this.findAllOptionsByMaterialId(materialid);
        // 删除对应的数据
        if (CollUtil.isNotEmpty(options)) {
            List<String> attachmentIds = options.stream().map(Aprv_materials_options::getAttachid).distinct().collect(Collectors.toList());
            // 删除对应的文件
            Map<String, Ha_attachment> attachmentMap = ha_attachmentService.getHa_attachmentMapByIds(attachmentIds);
            if (ObjectUtil.isNotNull(attachmentMap)) {
                for (Ha_attachment attachment : attachmentMap.values()) {
                    fileService.removeFile(attachment.getBucket(), attachment.getPath());
                    ha_attachmentService.removeById(attachment.getId());
                }
            }
            this.removeByIds(options.stream().map(Aprv_materials_options::getId).collect(Collectors.toList()));
        }
    }

    @Override
    public Map<String, List<Aprv_materials_options>> findOldOptionMaterialMap(List<String> materialIds) {
        if (CollUtil.isNotEmpty(materialIds)) {
            List<Aprv_materials_options> options = dao.findAllOptionsByMaterialIds(materialIds);
            if (CollUtil.isNotEmpty(options)) {
                findAttachMentByMeterial(options);
                return options.stream().collect(Collectors.groupingBy(Aprv_materials_options::getMaterialid));
            }
        }
        return Collections.emptyMap();
    }


    public void findAttachMentByMeterial(List<Aprv_materials_options> optionsList) {
        if (CollectionUtil.isNotEmpty(optionsList)) {
            List<String> attachmentIds = optionsList.stream().map(Aprv_materials_options::getAttachid).collect(Collectors.toList());
            Map<String, Ha_attachment> ha_attachmentMap = ha_attachmentService.getHa_attachmentsByIds(attachmentIds);
            if (ObjectUtil.isNotNull(ha_attachmentMap)) {
                optionsList.stream().forEach(m -> {
                    Optional.ofNullable(ha_attachmentMap.get(m.getAttachid())).ifPresent(then -> {
                        m.setFile(ha_attachmentMap.get(m.getAttachid()));
                    });
                });
            }
        }
    }
}
